pub mod executor;
pub mod string;
pub mod list;
pub mod hash;
pub mod set;
pub mod generic;

use crate::protocol::{RedisCommand, RespValue};
use crate::storage::{Storage, StorageEngine};
use std::sync::Arc;

pub use executor::*;

/// Command handler trait
pub trait CommandHandler {
    async fn execute(&self, storage: &Storage, command: RedisCommand) -> RespValue;
}

/// Command execution result
pub type CommandResult = RespValue;

/// Command executor
pub struct CommandExecutor {
    storage: Arc<Storage>,
}

impl CommandExecutor {
    /// Create a new command executor
    pub fn new(storage: Arc<Storage>) -> Self {
        Self { storage }
    }

    /// Execute a Redis command
    pub async fn execute(&self, command: RedisCommand) -> RespValue {
        match command.name.as_str() {
            // String commands
            "GET" => string::get(&*self.storage, command).await,
            "SET" => string::set(&*self.storage, command).await,
            "APPEND" => string::append(&*self.storage, command).await,
            "INCR" => string::incr(&*self.storage, command).await,
            "DECR" => string::decr(&*self.storage, command).await,

            // List commands
            "LPUSH" => list::lpush(&*self.storage, command).await,
            "RPUSH" => list::rpush(&*self.storage, command).await,
            "LPOP" => list::lpop(&*self.storage, command).await,
            "RPOP" => list::rpop(&*self.storage, command).await,
            "LLEN" => list::llen(&*self.storage, command).await,
            "LRANGE" => list::lrange(&*self.storage, command).await,

            // Hash commands
            "HSET" => hash::hset(&*self.storage, command).await,
            "HGET" => hash::hget(&*self.storage, command).await,
            "HDEL" => hash::hdel(&*self.storage, command).await,
            "HGETALL" => hash::hgetall(&*self.storage, command).await,
            "HEXISTS" => hash::hexists(&*self.storage, command).await,

            // Set commands
            "SADD" => set::sadd(&*self.storage, command).await,
            "SREM" => set::srem(&*self.storage, command).await,
            "SISMEMBER" => set::sismember(&*self.storage, command).await,
            "SMEMBERS" => set::smembers(&*self.storage, command).await,
            "SCARD" => set::scard(&*self.storage, command).await,

            // Generic commands
            "DEL" => generic::del(&*self.storage, command).await,
            "EXISTS" => generic::exists(&*self.storage, command).await,
            "KEYS" => generic::keys(&*self.storage, command).await,
            "TYPE" => generic::type_cmd(&*self.storage, command).await,
            "TTL" => generic::ttl(&*self.storage, command).await,
            "EXPIRE" => generic::expire(&*self.storage, command).await,
            "PERSIST" => generic::persist(&*self.storage, command).await,
            "FLUSHDB" => generic::flushdb(&*self.storage, command).await,

            // Server commands
            "PING" => generic::ping(&*self.storage, command).await,
            "ECHO" => generic::echo(&*self.storage, command).await,
            "TIME" => generic::time(&*self.storage, command).await,
            "INFO" => generic::info(&*self.storage, command).await,

            _ => RespValue::error(format!("ERR unknown command '{}'", command.name)),
        }
    }
}